package dev.ece.core.cells;

import java.util.Iterator;
import java.util.Stack;
import java.util.Vector;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lwjgl.opengl.GL11;

import dev.ece.core.clearup.ClearUpGLRubbishManager;
import dev.ece.util.GLUtils;
import dev.ece.util.arrays.ReverseIterator;
import dev.ece.util.tools.Camera;
import dev.ece.util.tools.Screen;
import dev.ece.util.tools.transformations.Transformation;
/**
 * 图元组
 * @author 飘渺青衣
 * <b>E-mail：</b>3375758@qq.com
 */
@SuppressWarnings("serial")
public class CellGroup<T extends Cell> extends Vector<T> implements Cell {

	private final Logger log = LogManager.getLogger(CellGroup.class);
	
	private boolean visible = true;
	
	private boolean logic = true;
	
	private boolean initialized;
	
	private static final Stack<Screen> ScissorStack = new Stack<Screen>();
	
	private static Screen currentScreen;
	
	public final Vector<Transformation> transformations = new Vector<Transformation>();
	
	public void glPushScissor(int x, int y, int width, int height) {
		if(currentScreen == null) {
			GL11.glEnable(GL11.GL_SCISSOR_TEST);
		} else {
			ScissorStack.push(currentScreen);
		}
		currentScreen = new Screen(x, y, width, height);
		glCurrentScissor();
	}
	
	public void glPopScissor() {
		if(ScissorStack.isEmpty()) {
			GL11.glDisable(GL11.GL_SCISSOR_TEST);
			currentScreen = null;
		} else {
			currentScreen = ScissorStack.pop();
			glCurrentScissor();
		}
	}
	
	protected void glCurrentScissor() {
		int left = currentScreen.getX();
		int bottom = currentScreen.getY();
		int width = currentScreen.getWidth();
		int height = currentScreen.getHeight();
		int top = bottom + height;
		int right = left + width;
		if(!ScissorStack.isEmpty()) {
			Iterator<Screen> it = ScissorStack.iterator();
			Screen screen = null;
			while(it.hasNext()) {
				screen = it.next();
				left = Math.max(left, screen.getX());
				bottom = Math.max(bottom, screen.getY());
				right = Math.min(right, screen.getX() + screen.getWidth());
				top = Math.min(top, screen.getY() + screen.getHeight());
			}
			width = right - left;
			height = top - bottom;
		}
		GL11.glScissor(left, bottom, width, height);
	}
	
	@Override
	public synchronized void logic(Camera camera) {
		try {
			this.onLogic(camera);
		} catch(Exception e) {
			log.error("逻辑计算异常", e);
		} 
		this.locicChildren(camera);
	}

	protected void locicChildren(Camera camera) {
		try {
			Iterator<T> it = this.iterator();
			T cell = null;
			while(it.hasNext()) {
				cell = it.next();
				if(cell.isVisible() && cell.isInitialized() && cell.isLogic()) {
					cell.logic(camera);
				}
			}
		} catch(Exception e) {
			log.error("下级逻辑计算异常", e);
		} 
	}
	
	@Override
	public synchronized void render(Camera camera) {
		GLUtils.glPushMatrix();
		try {
			this.calculate();
			this.onRender(camera);
		} catch(Exception e) {
			log.error("渲染异常", e);
		} 
		this.renderChildren(camera);
		GLUtils.glPopMatrix();
	}
	
	protected void renderChildren(Camera camera) {
		try {
			Iterator<T> it = this.iterator();
			T cell = null;
			while(it.hasNext()) {
				cell = it.next();
				if(cell.isVisible() && cell.isInitialized()) {
					cell.render(camera);
				}
			}
		} catch(Exception e) {
			log.error("下级渲染异常", e);
		}
	}
	
	public Iterator<T> reverseIterator() {
		return new ReverseIterator<T>(this);
	}
	
	@Override
	public boolean isVisible() {
		return visible;
	}

	@Override
	public boolean isLogic() {
		return logic;
	}

	public void setVisible(boolean visible) {
		this.visible = visible;
	}

	public void setLogic(boolean logic) {
		this.logic = logic;
	}

	@Override
	public void destroy() {
		this.setLogic(false);
		this.setVisible(false);
		ClearUpGLRubbishManager.push(this);
		Iterator<T> it = this.iterator();
		while(it.hasNext()) {
			it.next().destroy();
		}
		this.clear();
		transformations.clear();
	}
	
	@Override
	public void onLogic(Camera camera) {}

	@Override
	public void onRender(Camera camera) {}
	
	@Override
	public synchronized void initialize() {
		if(!this.isInitialized()) {
			try {
				this.onInitialize();
			} catch(Exception e) {
				log.error("初始化异常异常", e);
			}
			this.setInitialized(true);
		}
		this.initializeChildren();
	}
	
	protected void initializeChildren() {
		Iterator<T> it = this.iterator();
		while(it.hasNext()) {
			it.next().initialize();
		}
	}

	@Override
	public boolean isInitialized() {
		return initialized;
	}

	@Override
	public void setInitialized(boolean initialized) {
		this.initialized = initialized;
	}

	@Override
	public Vector<Transformation> getTransformations() {
		return transformations;
	}

	@Override
	public void clearup() {}

	@Override
	public void onInitialize() {}

	@Override
	public boolean equals(Object obj) {
		return this == obj;
	}
	
}
